package com.jvup.common.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 通知事件总线
 */
public class NoticeEventBus {

    /** 总线控制通知器 */
    public static final NoticeEventBus NOTICE = new NoticeEventBus();

    /** 通知事件队列 */
    private final ConcurrentLinkedQueue<NoticeEvent>            noticeEventQueue    = new ConcurrentLinkedQueue<>();
    /** 事件订阅者映射 */
    private final HashMap<String, ArrayList<EventSubscriber>>   eventSubscriberMap  = new HashMap<>();

    private NoticeEventBus() {
        // 如果有需求处理一些暂存恢复的操作，则可以再次来完成串行化存储以及恢复 队列和映射，
        // 并且对于事件和订阅者应该提供标准的串行接口这个接口可能需要一些特殊设计以满足恢复时应对特别的情况。
    }

    /** 订阅事件*/
    public void subscribeEvent(String eventTag, EventSubscriber eventSubscriber) {

        ArrayList<EventSubscriber> eventSubscriberList = eventSubscriberMap.get(eventTag);
        if(eventSubscriberList == null) {
            eventSubscriberList = new ArrayList<>();
            eventSubscriberMap.put(eventTag, eventSubscriberList);
        }
        eventSubscriberList.add(eventSubscriber);

    }

    /** 退订事件通过事件TAG*/
    public void unSubscribeEvent(String eventTag) {
        eventSubscriberMap.remove(eventTag);
    }

    /** 退订事件通过事件订阅者*/
    public void unSubscribeEvent(EventSubscriber event){
        for(ArrayList<EventSubscriber> list : eventSubscriberMap.values()) {
            if(list.contains(event)) {
                list.remove(event);
            }
        }
    }

    /** 批量释放事件订阅者*/
    public void release(ArrayList<EventSubscriber> eventSubscriberArrayList) {
        if(eventSubscriberArrayList == null || eventSubscriberArrayList.isEmpty()) {
            return;
        }
        for(EventSubscriber eventSubscriber : eventSubscriberArrayList) {
            unSubscribeEvent(eventSubscriber);
        }
    }

    /**
     * 无数据消息通知投递
     * @param tag   消息标签
     */
    public void sendEvent(String tag) {
        sendEvent(tag, null);
    }

    /**
     * 带数据的消息通知投递
     * @param tag   消息标签
     * @param data  消息数据
     * @param <T>   消息数据类型
     */
    public <T> void sendEvent(String tag, T data) {
        sendEvent(new NoticeEvent(tag, data));
    }

    /**
     * 投递自定义消息事件
     * @param event 自定义消息事件
     */
    public void sendEvent(NoticeEvent event) {
        noticeEventQueue.offer(event);
        dispenseEvent();
    }

    /** 互交事件分发*/
    private void dispenseEvent() {
        while(true) {
            NoticeEvent event = noticeEventQueue.poll();
            if(event == null) {
                return;
            }

            ArrayList<EventSubscriber> eventSubscriberList = eventSubscriberMap.get(event.tag);
            if(eventSubscriberList == null) {
                return;
            }

            for(EventSubscriber eventSubscriber : eventSubscriberList) {
                boolean handleState = eventSubscriber.doResponse(event);
                if(handleState && !event.haveTransitivity) {
                    break;
                }
            }
        }
    }

    /** 互交事件容器*/
    public static class NoticeEvent<T> {
        private final String tag;
        private final T eventData;
        private final boolean haveTransitivity;

        public NoticeEvent(String tag, T eventData){
            this(tag, eventData, true);
        }

        public NoticeEvent(String tag, T eventData, boolean haveTransitivity) {
            this.tag = tag;
            this.eventData = eventData;
            this.haveTransitivity = haveTransitivity;
        }

        public T getEventData() {
            return eventData;
        }
    }

    /** 互交事件订阅者*/
    public interface EventSubscriber<T> {
        /**
         * @param event 事件容器
         * @return boolean 事件是否需要继续传递给其他订阅者处理。true 不需要已处理了 false 需要*/
        boolean doResponse(NoticeEvent<T> event);
    }
}
